<template>
  <el-container style="width: 100%; height: 100%">
    <!-- 头部标题 -->
    <el-header class="header">射线</el-header>
    <!-- 主要内容区域，包含 Three.js 画布 -->
    <el-main class="canvas-container">
      <canvas ref="canvas" class="canvas"></canvas>
    </el-main>
  </el-container>
</template>

<script lang="ts">
export default {
  name: 'ThreeRaycaster', // 使用多词名称
}
</script>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

// Three.js 相关变量声明
// 场景
let scene: THREE.Scene
// 透视相机
let camera: THREE.PerspectiveCamera
// WebGL渲染器
let renderer: THREE.WebGLRenderer
// 动画帧ID
let animationFrameId: number
// 轨道控制器
let controls: InstanceType<typeof OrbitControls>
//横向射线
let raycaster: THREE.Raycaster
// 用于显示射线的辅助对象
let arrowHelper: THREE.ArrowHelper

// 画布引用
const canvas = ref<HTMLCanvasElement>()

// 组件挂载时初始化场景并开始动画
onMounted(() => {
  initScene()
  animate()
  // 添加窗口大小改变事件监听
  window.addEventListener('resize', onWindowResize)
})

// 初始化场景
function initScene() {
  if (!canvas.value) return

  // 获取画布尺寸
  const width = canvas.value.clientWidth
  const height = canvas.value.clientHeight

  // 创建场景
  scene = new THREE.Scene()
  // 设置场景背景颜色为浅灰色
  scene.background = new THREE.Color(0xf0f0f0)

  // 创建透视相机
  camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)

  // 创建WebGL渲染器
  renderer = new THREE.WebGLRenderer({ canvas: canvas.value, antialias: true })
  renderer.setSize(width, height)
  // 设置设备像素比，确保在高分辨率屏幕上清晰显示
  renderer.setPixelRatio(window.devicePixelRatio)

  // 设置相机位置
  camera.position.set(0, 0, 20)
  camera.lookAt(0, 0, 0)

  // 初始化轨道控制器
  //它的作用是控制相机，让相机可以自由的旋转，缩放，平移
  controls = new OrbitControls(camera, renderer.domElement)
  // 设置是否启用阻尼，阻尼越大，动画越慢
  controls.enableDamping = true
  // 设置阻尼系数，阻尼系数越大，动画越慢
  controls.dampingFactor = 0.05

  // 创建立方体
  const cube1 = new THREE.Mesh(
    new THREE.SphereGeometry(2, 32, 32),
    new THREE.MeshBasicMaterial({ color: 0xff11ff }),
  )
  cube1.position.set(-5, 0, 0)
  scene.add(cube1)
  const cube2 = new THREE.Mesh(
    new THREE.SphereGeometry(2, 32, 32),
    new THREE.MeshBasicMaterial({ color: 0xff11ff }),
  )
  cube2.position.set(5, 0, 0)
  scene.add(cube2)
  const cube3 = new THREE.Mesh(
    new THREE.SphereGeometry(2, 32, 32),
    new THREE.MeshBasicMaterial({ color: 0xff11ff }),
  )
  cube3.position.set(0, 5, 0)
  scene.add(cube3)
  raycaster = new THREE.Raycaster()
  const origin = new THREE.Vector3(-50, 0, 0) // 射线起点
  const direction = new THREE.Vector3(1, 0, 0).normalize() // 射线方向

  raycaster.set(origin, direction)

  // 使用 ArrowHelper 可视化射线
  const arrowLength = 80 // 箭头长度
  const arrowColor = 0xff0000 // 箭头颜色
  arrowHelper = new THREE.ArrowHelper(direction, origin, arrowLength, arrowColor)
  scene.add(arrowHelper)

}

// 动画循环函数
function animate() {
  scene.children.forEach((child) => {
    if ('material' in child && child.material instanceof THREE.MeshBasicMaterial) {
      const mesh = child as THREE.Mesh
      if (mesh.material instanceof THREE.MeshBasicMaterial) {
        mesh.material.color.set(0xff11ff)
      }
    }
  })

  raycaster.intersectObjects(scene.children).forEach((intersection) => {
    const object = intersection.object

    // 检查对象是否有 material 属性
    if ('material' in object && object.material instanceof THREE.Material) {
      // 使用类型断言确保对象具有 material 属性
      const mesh = object as THREE.Mesh
      // 确保 material 是单个材质，并且具有 color 属性
      if (mesh.material instanceof THREE.MeshBasicMaterial) {
        mesh.material.color.set(0x000000)
      } else if (Array.isArray(mesh.material)) {
        // 如果 material 是数组，遍历每个材质
        mesh.material.forEach((material) => {
          if ('color' in material) {
            ;(material as THREE.MeshBasicMaterial).color.set(0x000000)
          }
        })
      }
    }
  })
  animationFrameId = requestAnimationFrame(animate)
  // 更新控制器
  controls.update()
  // 渲染场景
  renderer.render(scene, camera)
}

// 清理函数
function cleanup() {
  // 取消动画帧
  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId)
  }

  // 清理渲染器
  if (renderer) {
    // 移除所有事件监听器
    renderer.domElement.removeEventListener('resize', onWindowResize)
    // 释放渲染器资源
    renderer.dispose()
    // 清空渲染器
    renderer.forceContextLoss()
    // 移除画布
    renderer.domElement.remove()
  }

  // 清理场景
  if (scene) {
    // 遍历场景中的所有对象
    scene.traverse((object) => {
      if (object instanceof THREE.Mesh) {
        // 释放几何体资源
        object.geometry.dispose()
        // 释放材质资源
        if (Array.isArray(object.material)) {
          object.material.forEach((material) => material.dispose())
        } else {
          object.material.dispose()
        }
      }
    })
    // 清空场景
    scene.clear()
  }

  // 清理相机
  if (camera) {
    camera.clear()
  }
}

// 窗口大小改变时的处理函数
function onWindowResize() {
  if (!canvas.value) return
  const width = canvas.value.clientWidth
  const height = canvas.value.clientHeight

  // 更新相机
  camera.aspect = width / height
  camera.updateProjectionMatrix()

  // 更新渲染器
  renderer.setSize(width, height)
}

// 组件卸载时清理资源
onUnmounted(() => {
  cleanup()
  // 移除窗口大小改变事件监听
  window.removeEventListener('resize', onWindowResize)
})
</script>

<style scoped>
/* 头部样式 */
.header {
  text-align: center;
  font-size: 20px;
  font-weight: bold;
  color: #333;
}

/* 画布容器样式 */
.canvas-container {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
}

/* 画布样式   // 保持画布比例*/
.canvas {
  width: 100%;
  height: 100%;
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
</style>
